package com.cq.hd.admin.config;

import com.cq.hd.admin.filter.JWTFilter;
import com.cq.hd.admin.shiro.*;
import org.apache.shiro.authc.AbstractAuthenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.*;

/**
 * Created with IntelliJ IDEA
 *
 * @Author pjwu
 * @Description
 * @Date 2019-05
 */
@Configuration
public class ShiroConfig {

    //是否开启swagger，正式环境一般是需要关闭的，可根据springboot的多环境配置进行设置
//    @Value(value = "${swagger.enabled}")
//    private Boolean swaggerEnabled;

    @Bean
    public ShiroFilterFactoryBean factory(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        //设置我们自定义的JWT过滤器
        filterMap.put("jwt", new JWTFilter());
        factoryBean.setFilters(filterMap);
        factoryBean.setSecurityManager(securityManager);
        // 设置无权限时跳转的 url;
        factoryBean.setUnauthorizedUrl("/unauthorized/无权限");

        //用LinkedHashMap保证顺序，否则setFilterChainDefinitionMap时会导致filterRuleMap.put("/**", "authc")先执行，导致部分无需登录即可访问的地址也需要登录才可访问
        Map<String, String> filterRuleMap = new LinkedHashMap<>();
        filterRuleMap.put("/unauthorized/**", "anon");
        filterRuleMap.put("/auth/login/**", "anon");
        filterRuleMap.put("/auth/mobileLogin/**", "anon");
        filterRuleMap.put("/auth/logout/**", "anon");
        filterRuleMap.put("/auth/401", "anon");
        filterRuleMap.put("/auth/index", "anon");
        filterRuleMap.put("/auth/403", "anon");
        filterRuleMap.put("/index/index", "anon");

        filterRuleMap.put("/sms/send/**", "anon");

        //swagger未开启则不开放swagger接口权限
//        if(swaggerEnabled){
        //swagger接口权限 开放
        filterRuleMap.put("/swagger-ui.html", "anon");
        filterRuleMap.put("/webjars/**", "anon");
        filterRuleMap.put("/v2/api-docs/**", "anon");
        filterRuleMap.put("/swagger-resources/**", "anon");
//        }
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了，登出后跳转配置的loginUrl
//        filterRuleMap.put("/logout", "logout");
        // <!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        //filterRuleMap的所有配置，/**配置必须放在最后不管是配置filterRuleMap.put("/**", "authc")还是filterRuleMap.put("/**", "anon")，/**配置完，后面再配的url可能会被/**覆盖
//        filterRuleMap.put("/**", "authc");
        filterRuleMap.put("/**", "jwt");
//        factoryBean.setLoginUrl("/auth/401");
//        factoryBean.setSuccessUrl("/auth/index");
//        factoryBean.setUnauthorizedUrl("/auth/403");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }

//    @Bean
//    public SessionManager sessionManager() {
//        return new AdminWebSessionManager();
//    }

    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager(TokenRealm tokenRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realms
        List<Realm> realms = new ArrayList<>();
        realms.add(tokenRealm);
//        realms.add(dbShiroRealm);
//        realms.add(mobileShiroRealm);
        securityManager.setRealms(realms);

        // 设置自定义 realm.
//        securityManager.setRealm(dbShiroRealm);
//        securityManager.setSessionManager(sessionManager());
        // 认证器
//        securityManager.setAuthenticator(abstractAuthenticator(dbShiroRealm, mobileShiroRealm, tokenRealm));


        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * 认证器
     */
//    @Bean
//    public AbstractAuthenticator abstractAuthenticator(TokenRealm tokenRealm) {
//        // 自定义模块化认证器，用于解决多realm抛出异常问题
//        ModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
//        // 认证策略：AtLeastOneSuccessfulStrategy(默认)，AllSuccessfulStrategy，FirstSuccessfulStrategy
//        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
//        // 加入realms
//        List<Realm> realms = new ArrayList<>();
////        realms.add(dbShiroRealm);
////        realms.add(mobileShiroRealm);
//        realms.add(tokenRealm);
//        authenticator.setRealms(realms);
//        return authenticator;
//    }
}